package br.com.srv.componentes.relatorio.estatisticaperimetro.service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import br.com.srv.commons.service.impl.BasicServiceImpl;
import br.com.srv.componentes.cerca.service.CercaService;
import br.com.srv.componentes.cerca.util.PontosTODataComparator;
import br.com.srv.componentes.cerca.util.PontosTODescricaoComparator;
import br.com.srv.componentes.jdbcdao.DadosLidoJdbcDAO;
import br.com.srv.componentes.relatorio.estatisticaperimetro.vo.EstatisticaPerimetroResultVO;
import br.com.srv.model.CercaTO;
import br.com.srv.model.PeriodoTO;
import br.com.srv.model.PontoTO;
import br.com.srv.model.VeiculoTO;
import br.com.srv.util.DateHelper;
import br.com.srv.util.geometriaanalitica.VerificadorVeiculoPoligono;

public class EstatisticaPerimetroServiceImpl extends BasicServiceImpl implements EstatisticaPerimetroService {
		
	CercaService cercaService;
	DadosLidoJdbcDAO dadosLidoJdbcDAO;

	public List<EstatisticaPerimetroResultVO> gerarDadosRelatorioByVeiculo(
			Integer veiculoId, CercaTO cercaTO, PeriodoTO periodoTO) throws Exception {
		
		List<EstatisticaPerimetroResultVO> resultadoLista =
			new ArrayList<EstatisticaPerimetroResultVO>();
		
		//pegar cercas
		List<CercaTO> cercas = cercaService.buscarCercasAtivas(cercaTO);
		
		//passar data para formato aceito no DB.
		String dataInicial = DateHelper.parseStringDateToStringDateJdbc(
				periodoTO.getDataInicial());
		String dataFinal = DateHelper.parseStringDateToStringDateJdbc(
				periodoTO.getDataFinal());
		
		//Pegar pontos do veiculo
		List<Map<String, String>> pontos = getDadosLidoJdbcDAO().consultaPontosByVeiculo(
				veiculoId.toString(), dataInicial, dataFinal,
				periodoTO.getHoraInicial(), periodoTO.getHoraFinal());
		
		List<PontoTO> pontosVeiculo = gerarListaPontoTOs(pontos);
		
		VerificadorVeiculoPoligono verificadorVeiculoCerca = new VerificadorVeiculoPoligono();
		for (CercaTO cercaTODB : cercas) {

			List<PontoTO> pontosOrdenados = new ArrayList<PontoTO>();
			pontosOrdenados.addAll(cercaTODB.getPontos());
			
			//ordena pontos da cerca
			Collections.sort(pontosOrdenados, new PontosTODescricaoComparator());
			
			//ordena pontos do veiculo
			Collections.sort(pontosVeiculo, new PontosTODataComparator());
	
			boolean flag = false;
			boolean flagAnterior = false;
			String dataEntrada = null;
			String dataSaida = null;
			EstatisticaPerimetroResultVO vo = null;
			
			for (Iterator iter = pontosVeiculo.iterator(); iter.hasNext();) {
				PontoTO pontoTO = (PontoTO) iter.next();
					
				flagAnterior = flag;
				flag = verificadorVeiculoCerca.contem(pontoTO, pontosOrdenados);
				
				//se mudou de status
				if (flag != flagAnterior) {
					if (flag == true) {
						dataEntrada = pontoTO.getDataHora();
						
						vo = new EstatisticaPerimetroResultVO();
						vo.setCercaId(cercaTODB.getId());
						vo.setCercaCodigo(cercaTODB.getCodigo());
						vo.setDataHoraEntrada(dataEntrada);
						
					} else {
						dataSaida =  pontoTO.getDataHora();
											
						vo.setDataHoraSaida(dataSaida);
						vo.setTempoPermanencia(calcularIntervalo(dataEntrada, dataSaida));
						resultadoLista.add(vo);
					}
				}				
			}
			//se iterar todos os pontos e o veiculo tiver entrado na cerca
			//mas n�o tiver sa�do
			if (flagAnterior) {
				dataSaida = pontosVeiculo.get(pontosVeiculo.size()-1).getDataHora();
				vo.setDataHoraSaida(dataSaida);
				vo.setTempoPermanencia(calcularIntervalo(dataEntrada, dataSaida));
				resultadoLista.add(vo);		
			}
		}
		return resultadoLista;		
	}

	public List<EstatisticaPerimetroResultVO> gerarDadosRelatorioByCerca(CercaTO cercaTO,
			PeriodoTO periodoTO) throws Exception {
		
		List<EstatisticaPerimetroResultVO> resultadoLista = new ArrayList<EstatisticaPerimetroResultVO>();
		
		//buscar cerca
		cercaTO = cercaService.buscarCercaById(cercaTO.getId().toString());
		
		//ordena pontos da cerca
		List<PontoTO> pontosCerca = new ArrayList<PontoTO>();
		pontosCerca.addAll(cercaTO.getPontos());
		Collections.sort(pontosCerca, new PontosTODescricaoComparator());
		
		//buscar veiculos da cerca
		List<VeiculoTO> veiculos = cercaService.buscarVeiculosDaCerca(cercaTO.getId());
		
		VerificadorVeiculoPoligono verificadorVeiculoCerca = new VerificadorVeiculoPoligono();
		
		for (VeiculoTO veiculo : veiculos) {
			
			//passar data para formato aceito no DB.
			String dataInicial = DateHelper.parseStringDateToStringDateJdbc(
					periodoTO.getDataInicial());
			String dataFinal = DateHelper.parseStringDateToStringDateJdbc(
					periodoTO.getDataFinal());
			
			//Pegar pontos do veiculo
			List<Map<String, String>> pontos = getDadosLidoJdbcDAO().consultaPontosByVeiculo(
					veiculo.getRealId().toString(), dataInicial, dataFinal,
					periodoTO.getHoraInicial(), periodoTO.getHoraFinal());
			
			List<PontoTO> pontosVeiculo = gerarListaPontoTOs(pontos);
			
			//ordena pontos do veiculo
			Collections.sort(pontosVeiculo, new PontosTODataComparator());
			
			boolean flag = false;
			boolean flagAnterior = false;
			String dataEntrada = null;
			String dataSaida = null;
			EstatisticaPerimetroResultVO vo = null;
			
			for (PontoTO pontoVeiculo : pontosVeiculo) {
				flagAnterior = flag;
				flag = verificadorVeiculoCerca.contem(pontoVeiculo, pontosCerca);
				
				//se mudou de status
				if (flag != flagAnterior) {
					if (flag == true) {
						System.out.println("entrou na cerca");
						dataEntrada = pontoVeiculo.getDataHora();
						
						vo = new EstatisticaPerimetroResultVO();
						vo.setVeiculoId(veiculo.getId());
						vo.setVeiculoDescricao(veiculo.getDescricao());
						vo.setDataHoraEntrada(dataEntrada);
						
					} else {
						System.out.println("saiu da cerca");
						dataSaida =  pontoVeiculo.getDataHora();
											
						System.out.println("parada em minutos: " + calcularIntervalo(dataEntrada, dataSaida));
						vo.setDataHoraSaida(dataSaida);
						vo.setTempoPermanencia(calcularIntervalo(dataEntrada, dataSaida));
						resultadoLista.add(vo);
					}
				}	
			}
			//se iterar todos os pontos e o veiculo tiver entrado na cerca
			//mas n�o tiver sa�do
			if (flagAnterior) {
				dataSaida = pontosVeiculo.get(pontosVeiculo.size()-1).getDataHora();
				vo.setDataHoraSaida(dataSaida);
				vo.setTempoPermanencia(calcularIntervalo(dataEntrada, dataSaida));
				resultadoLista.add(vo);		
			}
		}
		
		return resultadoLista;
	}

	private List<PontoTO> gerarListaPontoTOs(List<Map<String, String>> pontos) {
		List<PontoTO> pontosVeiculo = new ArrayList<PontoTO>();
		for (Map mapa : pontos) {
			PontoTO pontoTO = new PontoTO();
			pontoTO.setDataHora((String)mapa.get("DATE_TIME"));
			pontoTO.setLongitude(new Double((String)mapa.get("X")));
			pontoTO.setLatitude(new Double((String)mapa.get("Y")));	
			pontoTO.setVelocidade(new Double((String)mapa.get("VEL")));	
			pontoTO.setDistanciaUltimoPonto(new Double((String)mapa.get("DIST_BETWEEN_POSITIONS")));
			pontoTO.setDescricao((String)mapa.get("NEAR_DESC"));
			pontosVeiculo.add(pontoTO);
		}
		return pontosVeiculo;
	}
	
	private String calcularIntervalo(String dataEntrada, String dataSaida) throws ParseException {		
		long entrada = DateHelper.parseDate(DateHelper.REPORT_DATE_DEFAULT, dataEntrada).getTime();
		long saida = DateHelper.parseDate(DateHelper.REPORT_DATE_DEFAULT, dataSaida).getTime();
		
		long emMinutos = ((saida - entrada)/1000)/60; 
		Long horas = emMinutos/60;
		long restoMinuto = emMinutos % 60;
		
		String result = "";
		
		if (horas < 10) {
			result += "0";
		}
		
		result +=  horas + ":";
		
		if (restoMinuto < 10){
			result += "0";
		}
		return  result + restoMinuto;
	}

	public DadosLidoJdbcDAO getDadosLidoJdbcDAO() {
		return dadosLidoJdbcDAO;
	}

	public void setDadosLidoJdbcDAO(DadosLidoJdbcDAO dadosLidoJdbcDAO) {
		this.dadosLidoJdbcDAO = dadosLidoJdbcDAO;
	}
	public CercaService getCercaService() {
		return cercaService;
	}
	
	public void setCercaService(CercaService cercaService) {
		this.cercaService = cercaService;
	}	
}
